home *** CD-ROM | disk | FTP | other *** search
- /*
- * ptmidzap.c: Resolution module for ptmid. Takes a structure representing
- * a tune and tries to make it fit into 4 channels.
- *
- * Author: Andrew Scott (c)opyright 1994
- *
- * Date: 17/11/1993 ver 0.0
- * 8/1/1994 ver 0.1
- * 11/2/1994 ver 0.2
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include "ptmid.h"
-
- MS rgmsDecided[MAXSAMPS];
- int cmsDecided, wMinpitch, wMaxpitch;
-
- /**
- ** The midivolume array holds Protracker equivants of MIDI velocities.
- ** It allows fast velocity-volume conversion.
- **/
- unsigned midivolume[128] = {
- 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
- 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
- 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
- 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64,
- 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64
- };
-
- /*
- * Init: Initializes stuff that should be initialized.
- *
- * date: 1/7/1994 - added init of min/max pitches & default period array
- */
- static void Init(void)
- {
- int ims = MAXSAMPS;
-
- while (ims--) { /** Put default values in sample array **/
- sprintf(rgmsDecided[ims].szName, "%02d: --", ims);
- rgmsDecided[ims].psi = NULL;
- rgmsDecided[ims].bDefvol = 0;
- }
- cmsDecided = 0;
- if (fExtend) {
- wMinpitch = MIDDLEC - 24;
- wMaxpitch = MIDDLEC + 36;
- } else {
- wMinpitch = MIDDLEC - 12;
- wMaxpitch = MIDDLEC + 24;
- }
- }
-
- /*
- * FitSzBFn: Given a filename, will fit it into the given sample name,
- * and prepend given number, ensuring that it doesn't overflow the
- * 22 character array.
- */
- void FitSzBFn(Sz szName, int bPos, Sz fnSample)
- {
- int iT = 18;
-
- sprintf(szName, "%02d: ", bPos); /** First the number **/
- szName += 4;
- while (iT-- && (*(szName++) = *(fnSample++))); /** Then the name **/
- }
-
- /*
- * WConvertMidipitch: Given a MIDI pitch, returns a pitch in the range
- * allowed for output. If none can be found (only for wRgmode = 0), -2 is
- * returned. If the pitch is out of range, then the value of the given
- * pointer is incremented.
- *
- * date: 1/7/1994
- */
- int WConvertMidipitch(int pitch, unsigned long *cDev)
- {
- switch (wRgmode) {
- case 0:
- if (pitch < wMinpitch) {
- if (fStats)
- (*cDev)++;
- pitch = wMinpitch;
- } else if (pitch >= wMaxpitch) {
- if (fStats)
- (*cDev)++;
- pitch = wMaxpitch - 1;
- }
- break;
- case 1:
- if (pitch < wMinpitch || pitch >= wMaxpitch) {
- if (fStats)
- (*cDev)++;
- pitch = -2;
- }
- break;
- case 2:
- if (pitch < wMinpitch) {
- if (fStats)
- (*cDev)++;
- pitch += ((wMinpitch - pitch + 11) / 12) * 12;
- } else if (pitch >= wMaxpitch) {
- if (fStats)
- (*cDev)++;
- pitch -= ((pitch - wMaxpitch + 12) / 12) * 12;
- }
- }
- return pitch;
- }
-
- /*
- * AnalyzePtune: Given a tune, searches through and allocates samples
- * to sample array rgmsDecided (includes determining mixes).
- * Eventually (?) this will become much more extensive, and include
- * compacting by changing tempo, filtering of quiet notes, and identification
- * of common chords and replacing these with a separate sample.
- *
- * date: 1/7/1994 - added calls to WConvertMidipitch
- */
- void AnalyzePtune(Tune *ptune)
- {
- unsigned long Lastnoise = 0, cDev = 0;
- EI *pei;
- SI *psi, **ppsi;
-
- while (NULL != ptune) { /** While not at end of tune **/
- for (pei = ptune->pei; NULL != pei; pei = pei->pei) { /** With each event **/
- if (-1 != pei->pitch) {
- if (ptune->count + pei->effect > Lastnoise) /** Find the note which **/
- Lastnoise = ptune->count + pei->effect; /** will carry the longest **/
-
- if (pei->inst < 0) /** If a percussion instrument **/
- if ((psi = rgpsiDrum[-1 - pei->inst]) == NULL)
- pei->pitch = -2;
- else
- pei->pitch = WConvertMidipitch(MIDDLEC + psi->perpitch -
- psi->pitch, &cDev);
- else { /** Else if a non-percussion instrument **/
- unsigned wMin;
-
- if ((ppsi = rgppsiIns[pei->inst]) == NULL)
- ppsi = rgppsiIns[128];
- psi = *(ppsi++);
- wMin = abs(psi->pitch - pei->pitch);
- for (; NULL != *ppsi; ppsi++) /** Find closest matching sample **/
- if (abs((*ppsi)->pitch - pei->pitch) < wMin) {
- psi = *ppsi;
- wMin = abs(psi->pitch - pei->pitch);
- }
- pei->pitch = WConvertMidipitch(MIDDLEC + pei->pitch - psi->pitch,
- &cDev);
- }
- pei->vol = midivolume[pei->vol]; /** Convert volumes **/
-
- if (NULL != psi) /** If sample info **/
- if (-1 != psi->sample) /** and sample has been used before **/
- pei->inst = psi->sample; /** use that sample for instrument **/
- else if (MAXSAMPS == cmsDecided) /** Else if no samples left **/
- pei->pitch = -2; /** make note invalid **/
-
- else { /** Else we've got a new sample **/
- FitSzBFn(rgmsDecided[cmsDecided].szName, cmsDecided,
- psi->fnSample); /** Fix up it's name **/
- rgmsDecided[cmsDecided].bDefvol = 64;
- rgmsDecided[cmsDecided].psi = psi;
- psi->sample = pei->inst = cmsDecided++;
- }
- }
- }
- ptune = ptune->ptune;
- }
- if (fStats)
- printf(" Number of pitch conversions out of range: %lu\n", cDev);
- }
-
- /*
- * UnitifyPtune: Given a tune, will convert lengths into division multiples.
- */
- void UnitifyPtune(Tune *ptune)
- {
- EI *pei;
-
- while (NULL != ptune) { /** While not end of tune **/
- pei = ptune->pei;
- ptune->count /= wQuant; /** Divide intervals by quantize amount **/
- ptune = ptune->ptune;
- while (NULL != pei) { /** Go through each event **/
- if (-1 != pei->pitch)
- pei->effect /= wQuant; /** Divide durations by quantize amount **/
- pei = pei->pei;
- }
- }
- }
-
- /*
- * ResolvePtune: Given a tune, goes through and finds out useful stuff
- * about it for use in creating a MOD-file. Also trims off chords that
- * are too big, notes that are too quiet, etc.
- */
- void ResolvePtune(Tune *ptune)
- {
- Init();
- #if 0
- FilterPtune(ptune);
- Calcchords();
- ConvertPtune(ptune);
- Storevols();
- #endif
- AnalyzePtune(ptune);
- UnitifyPtune(ptune);
- }
-